using System;
using System.IO;
using System.Text;
using System.Collections;
using System.Reflection;


namespace Zeus.DotNetScript
{
	public enum DotNetLanguage 
	{
		CSharp = 0,
		VBNet
	}

	/// <summary>
	/// Summary description for DotNetScriptEngine.
	/// </summary>
	public class DotNetScriptEngine : IZeusScriptingEngine
	{
		protected DotNetScriptCodeParser _dotNetScriptCodeParser = null;
		protected DotNetScriptExecutioner _dotNetScriptExecutioner = null;

		internal const string DEBUG_FILE_PREFIX = "$ZEUS$DEBUG$";
		internal const string DLLREF = "DLLREF";
		internal const string USE_NAMESPACE = "USE";
		internal const string DEBUG = "DEBUG";
        internal const string VERSION = "VERSION";

		protected string[] _supportedLanguages = new string[] 
			   { 
				   ZeusConstants.Languages.CSHARP, 
				   ZeusConstants.Languages.VBNET 
			   };

		public DotNetScriptEngine() 
		{
			CleanupOldDebugFiles();
		}

		public string EngineName
		{
			get { return ZeusConstants.Engines.DOT_NET_SCRIPT; }
		}

		public IZeusCodeParser CodeParser
		{
			get 
			{
				if (_dotNetScriptCodeParser == null) 
				{
					_dotNetScriptCodeParser = new DotNetScriptCodeParser(this);
				}
				return _dotNetScriptCodeParser;
			}
		}

		public IZeusExecutionHelper ExecutionHelper
		{
			get 
			{
				if (_dotNetScriptExecutioner == null) 
				{
					_dotNetScriptExecutioner = new DotNetScriptExecutioner(this);
				}
				return _dotNetScriptExecutioner;
			}
		}

		public string[] SupportedLanguages
		{
			get { return _supportedLanguages; }
		}

		public bool IsSupportedLanguage(string language) 
		{
			foreach (string lang in _supportedLanguages) 
			{
				if (lang == language) return true;
			}
			return false;
		}

		public bool Execute(IZeusInput input, IZeusOutput output, string code)
		{
			return false;
		}

		#region Build extending Referece list classes
		
		internal ArrayList BuildDLLNames(IZeusContext context) 
		{
			ArrayList list = new ArrayList();

			if (context.IntrinsicObjects != null) 
			{
				foreach (IZeusIntrinsicObject scriptingObj in context.IntrinsicObjects)
				{
                    if (!scriptingObj.Disabled)
                    {
                        if (scriptingObj.DllReference != null)
                        {
                            if (!list.Contains(scriptingObj.DllReference))
                                list.Add(scriptingObj.DllReference);
                        }
                    }
				}
			}

			return list;
		}
		
		internal string BuildImportStatments(string language, ArrayList references) 
		{
			StringBuilder builder = new StringBuilder();

			foreach (string ns in references)
			{
				if (language == ZeusConstants.Languages.CSHARP) 
				{
					builder.Append("using ");
					builder.Append(ns);
					builder.Append(";\r\n");
				}
				else if (language == ZeusConstants.Languages.VBNET) 
				{
					builder.Append("Imports ");
					builder.Append(ns);
					builder.Append("\r\n");
				}
			}

			return builder.ToString();
		}

		internal string BuildGuiClass(string language, IZeusIntrinsicObject[] iobjs) 
		{		
			StringBuilder builder = new StringBuilder();

			if (language == ZeusConstants.Languages.CSHARP) 
			{
				builder.Append("//-- Class DotNetScriptGui Generated by Zeus\r\n");
				builder.Append("namespace Zeus.DotNetScript\r\n");
				builder.Append("{\r\n");
				builder.Append("\tpublic abstract class DotNetScriptGui : _DotNetScriptGui\r\n");
				builder.Append("\t{\r\n");

				foreach (IZeusIntrinsicObject scriptingObj in iobjs)
				{
                    if (!scriptingObj.Disabled)
                    {
                        builder.Append("\t\tprotected ");
                        builder.Append(scriptingObj.ClassPath);
                        builder.Append(" ");
                        builder.Append(scriptingObj.VariableName);
                        builder.Append(";\r\n");
                    }
				}

				builder.Append("\t\tpublic DotNetScriptGui(IZeusContext context) : base(context)\r\n");
				builder.Append("\t\t{\r\n");;
			
				foreach (IZeusIntrinsicObject scriptingObj in iobjs)
				{
                    if (!scriptingObj.Disabled)
                    {
                        builder.Append("\t\t\tthis.");
                        builder.Append(scriptingObj.VariableName);
                        builder.Append(" = context.Objects[\"");
                        builder.Append(scriptingObj.VariableName);
                        builder.Append("\"] as ");
                        builder.Append(scriptingObj.ClassPath);
                        builder.Append(";\r\n");
                    }
				}
		
				builder.Append("\t\t}\r\n\t}\r\n}\r\n");
			}
			else if (language == ZeusConstants.Languages.VBNET) 
			{
				builder.Append("'-- Class DotNetScriptGui Generated by Zeus\r\n");
				builder.Append("Public MustInherit Class DotNetScriptGui\r\n");
				builder.Append("\t\tInherits _DotNetScriptGui\r\n");

				foreach (IZeusIntrinsicObject scriptingObj in iobjs)
                {
                    if (!scriptingObj.Disabled)
                    {
                        builder.Append("\tProtected ");
                        builder.Append(scriptingObj.VariableName);
                        builder.Append(" As ");
                        builder.Append(scriptingObj.ClassPath);
                        builder.Append("\r\n");
                    }
				}

				builder.Append("\tPublic Sub New(context As IZeusContext)\r\n");
				builder.Append("\t\tMyBase.New(context)\r\n");

				foreach (IZeusIntrinsicObject scriptingObj in iobjs)
                {
                    if (!scriptingObj.Disabled)
                    {
                        builder.Append("\t\tMe.");
                        builder.Append(scriptingObj.VariableName);
                        builder.Append(" = CType(context.Objects.Item(\"");
                        builder.Append(scriptingObj.VariableName);
                        builder.Append("\"), ");
                        builder.Append(scriptingObj.ClassPath);
                        builder.Append(")\r\n");
                    }
				}
		
				builder.Append("\tEnd Sub\r\nEnd Class\r\n");
			}
			
			return builder.ToString();
		}

		internal string BuildBodyClass(string language, IZeusIntrinsicObject[] iobjs) 
		{		
			StringBuilder builder = new StringBuilder();

			if (language == ZeusConstants.Languages.CSHARP)
			{
				builder.Append("//-- Class DotNetScriptTemplate Generated by Zeus\r\n");
				builder.Append("namespace Zeus.DotNetScript\r\n");
				builder.Append("{\r\n");
				builder.Append("\tpublic abstract class DotNetScriptTemplate : _DotNetScriptTemplate\r\n");
				builder.Append("\t{\r\n");

				foreach (IZeusIntrinsicObject scriptingObj in iobjs)
				{
                    if (!scriptingObj.Disabled)
                    {
                        builder.Append("\t\tprotected ");
                        builder.Append(scriptingObj.ClassPath);
                        builder.Append(" ");
                        builder.Append(scriptingObj.VariableName);
                        builder.Append(";\r\n");
                    }
				}		

				builder.Append("\t\tpublic DotNetScriptTemplate(IZeusContext context) : base(context)\r\n");
				builder.Append("\t\t{\r\n");

				foreach (IZeusIntrinsicObject scriptingObj in iobjs)
				{
                    if (!scriptingObj.Disabled)
                    {
                        builder.Append("\t\t\tthis.");
                        builder.Append(scriptingObj.VariableName);
                        builder.Append(" = context.Objects[\"");
                        builder.Append(scriptingObj.VariableName);
                        builder.Append("\"] as ");
                        builder.Append(scriptingObj.ClassPath);
                        builder.Append(";\r\n");
                    }
				}
			
				builder.Append("\t\t}\r\n\t}\r\n}\r\n");
			}
			else if (language == ZeusConstants.Languages.VBNET) 
			{
				builder.Append("'-- Class DotNetScriptTemplate Generated by Zeus\r\n");
				builder.Append("Public MustInherit Class DotNetScriptTemplate\r\n");
				builder.Append("\t\tInherits _DotNetScriptTemplate\r\n");

				foreach (IZeusIntrinsicObject scriptingObj in iobjs)
                {
                    if (!scriptingObj.Disabled)
                    {
                        builder.Append("\tProtected ");
                        builder.Append(scriptingObj.VariableName);
                        builder.Append(" As ");
                        builder.Append(scriptingObj.ClassPath);
                        builder.Append("\r\n");
                    }
				}

				builder.Append("\tPublic Sub New(context As IZeusContext)\r\n");
				builder.Append("\t\tMyBase.New(context)\r\n");

				foreach (IZeusIntrinsicObject scriptingObj in iobjs)
				{
                    if (!scriptingObj.Disabled)
                    {
                        builder.Append("\t\tMe.");
                        builder.Append(scriptingObj.VariableName);
                        builder.Append(" = CType(context.Objects.Item(\"");
                        builder.Append(scriptingObj.VariableName);
                        builder.Append("\"), ");
                        builder.Append(scriptingObj.ClassPath);
                        builder.Append(")\r\n");
                    }
				}
		
				builder.Append("\tEnd Sub\r\nEnd Class\r\n");
			}

			return builder.ToString();
		}
		#endregion

		#region Default text for a new template
		public string GetNewTemplateText(string language)
		{
			StringBuilder builder = new StringBuilder();

			if (language == ZeusConstants.Languages.VBNET)
			{
				//Set the Body Text
				builder.Append("<%\r\n");
				builder.Append("Public Class GeneratedTemplate\r\n");
				builder.Append("\t\t\tInherits DotNetScriptTemplate\r\n");
				builder.Append("\r\n");
				builder.Append("\tPublic Sub New(context As ZeusContext)\r\n");
				builder.Append("\t\tMyBase.New(context)\r\n");
				builder.Append("\tEnd Sub\r\n");
				builder.Append("\r\n");
				builder.Append("\t'---------------------------------------------------\r\n");
    			builder.Append("\t' Render() is where you want to write your logic    \r\n");
    			builder.Append("\t'---------------------------------------------------\r\n");
				builder.Append("\tPublic Overrides Sub Render\r\n");
				builder.Append("\t\t%>\r\n");
				builder.Append("\t\tYou can toggle in and out of script like this\r\n");
				builder.Append("\t\t<%\r\n");
				builder.Append("\t\toutput.writeLn (\"Hello world.\")\r\n");
				builder.Append("\tEnd Sub\r\n");
				builder.Append("\r\n");
				builder.Append("End Class\r\n");
				builder.Append("%>");
			}
			else if (language == ZeusConstants.Languages.CSHARP)
			{
				//Set the Body Text
				builder.Append("<%\r\n");
				builder.Append("public class GeneratedTemplate : DotNetScriptTemplate\r\n");
				builder.Append("{\r\n");
				builder.Append("\tpublic GeneratedTemplate(ZeusContext context) : base(context) {}\r\n");
				builder.Append("\r\n");
				builder.Append("\t//---------------------------------------------------\r\n");
				builder.Append("\t// Render() is where you want to write your logic    \r\n");
				builder.Append("\t//---------------------------------------------------\r\n");
				builder.Append("\tpublic override void Render()\r\n");
				builder.Append("\t{\r\n");
				builder.Append("\t\t%>\r\n");
				builder.Append("\t\tYou can toggle in out of script like this\r\n");
				builder.Append("\t\t<%\r\n");
				builder.Append("\t\toutput.writeln(\"Hello world.\");\r\n");
				builder.Append("\t}\r\n");
				builder.Append("\r\n");
				builder.Append("}\r\n");
				builder.Append("%>");
			}

			return builder.ToString();
		}

		public string GetNewGuiText(string language)
		{
			StringBuilder builder = new StringBuilder();

			if (language == ZeusConstants.Languages.VBNET)
			{
				//Set the Interface Text
				builder.Append("\r\n");
				builder.Append("Public Class GeneratedGui\r\n");
				builder.Append("\t\t\tInherits DotNetScriptGui\r\n");
				builder.Append("\r\n");
				builder.Append("\tPublic Sub New(context As ZeusContext)\r\n");
				builder.Append("\t\tMyBase.New(context)\r\n");
				builder.Append("\tEnd Sub\r\n");
				builder.Append("\r\n");
				builder.Append("\t'-----------------------------------------\r\n");
				builder.Append("\t' The User Interface Entry Point\r\n");
				builder.Append("\t'-----------------------------------------\r\n");
				builder.Append("\tPublic Overrides Sub Setup\r\n\r");
	    		builder.Append("\t\t' ** UNCOMMENT CODE BELOW TO SEE UI **\r\n\r");
				builder.Append("\t\t'ui.Width  = 100\r\n");
				builder.Append("\t\t'ui.Height = 100\r\n");
				builder.Append("\t\t'Dim lblDemo As GuiLabel = ui.AddLabel(\"lblDemo\", \"Demo\", \"Demo Tooltip\")\r\n");
				builder.Append("\t\t'ui.ShowGui = true\r\n");
				builder.Append("\tEnd Sub\r\n");
				builder.Append("\r\n");
				builder.Append("End Class");
			}
			else if (language == ZeusConstants.Languages.CSHARP)
			{
				//Set the Interface Text
				builder.Append("\r\n");
				builder.Append("public class GeneratedGui : DotNetScriptGui\r\n");
				builder.Append("{\r\n");
				builder.Append("\tpublic GeneratedGui(ZeusContext context) : base(context) {}\r\n");
				builder.Append("\r\n");
				builder.Append("\t//-----------------------------------------\r\n");
				builder.Append("\t// The User Interface Entry Point\r\n");
				builder.Append("\t//-----------------------------------------\r\n");
				builder.Append("\tpublic override void Setup()\r\n");
				builder.Append("\t{\r\n");
				builder.Append("\t\t// ** UNCOMMENT CODE BELOW TO SEE UI **\r\n\r");
				builder.Append("\t\t//ui.Width  = 100;\r\n");
				builder.Append("\t\t//ui.Height = 100;\r\n");
				builder.Append("\t\t//GuiLabel lblDemo = ui.AddLabel(\"lblDemo\", \"Demo\", \"Demo Tooltip\");\r\n");
				builder.Append("\t\t//ui.ShowGui = true;\r\n");
				builder.Append("\t}\r\n");
				builder.Append("\r\n");
				builder.Append("}");
			}

			return builder.ToString();
		}
		#endregion

		private void CleanupOldDebugFiles() 
		{
			string location = Assembly.GetExecutingAssembly().Location;
			int index = location.LastIndexOf("\\");
			if (index >= 0) 
			{
				location = location.Substring(0, index);
				DirectoryInfo dir = new DirectoryInfo(location);
				foreach (FileInfo f in dir.GetFiles()) 
				{
					if (f.Name.StartsWith(DEBUG_FILE_PREFIX)) 
					{
						try { f.Delete(); } 
						catch {}
					}
				}
			}
		}

		#region Static File Methods
		public static string MakeAbsolute(string pathToChange, string basePath) 
		{
			string newPath = pathToChange;

			DirectoryInfo dinfo = new DirectoryInfo(basePath);
			string p1 = dinfo.FullName;
			if (!p1.EndsWith("\\")) p1 += "\\";

			if (dinfo.Exists) 
			{
				if (pathToChange.StartsWith("\\"))
				{
					newPath = dinfo.Root + pathToChange;
				}
				else if ((pathToChange.StartsWith(".")) ||
					(pathToChange.IndexOf(":") == -1))
				{
					newPath = p1 + pathToChange;
				}

				FileInfo finfo = new FileInfo(newPath);
				if (finfo.Exists) 
				{
					newPath = finfo.FullName;
				}
				else
				{
					finfo = new FileInfo(pathToChange);
					if (finfo.Exists) 
					{
						newPath = finfo.FullName;
					}
				}

			}

			return newPath;
		}
		#endregion

	}
}
